﻿using MotionControl.Core.Mvvm;
using MotionControl.Services.Interfaces;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MotionControl.Modules.PLC.Business;
using System.Threading;
using System.IO;
using System.Windows.Input;
using System.Xml.Linq;
using MotionControl.Core;
using Prism.Events;
using NLog;
using System.ComponentModel;
using Prism.Ioc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.ObjectModel;
using System.Security.Policy;
using System.Windows.Controls;

namespace MotionControl.Modules.PLC.ViewModels
{
    struct PLC_CMD
    {
        string name;
        int value;
    }

    public partial class PLCViewModel : RegionViewModelBase
    {
        private string _message;
        public string Message
        {
            get { return _message; }
            set { SetProperty(ref _message, value); }
        }

        public DelegateCommand<string> AxisCommand { get; private set; }
        public DelegateCommand<string> BoolCommand { get; private set; }

        public DelegateCommand<MouseButtonEventArgs> MouseDownCommand { get; private set; }
        public DelegateCommand<MouseButtonEventArgs> MouseUpCommand { get; private set; }

        public MonitorList monitorList { get; set; } = new MonitorList();
        public FloatList floatList { get; set; } = FloatList.GetInstance;
        public BoolList boolList { get; set; } = BoolList.GetInstance;
        public AxisPositions axisPos { get; set; } = new AxisPositions();

        private IEventAggregator _eventAgg;

        private ILogger _logger;

        private const string jsonFilePath = "data/plc_network.json";
        private NetInfo NetInfo { set; get; } = new NetInfo() 
        {IP = "192.168.10.12", Port = 502 };

        public PLCViewModel(IRegionManager regionManager, IContainerExtension container, IEventAggregator aggregator, ILogger logger) :
            base(regionManager)
        {
            _eventAgg = aggregator;
            _logger = logger;
            AxisCommand = new DelegateCommand<string>(OnAxisCommand);
            BoolCommand = new DelegateCommand<string>(OnBoolCommand);
            MouseDownCommand = new DelegateCommand<MouseButtonEventArgs>(OnMouseDownCommand);
            MouseUpCommand = new DelegateCommand<MouseButtonEventArgs>(OnMouseUpCommand);

            //container.RegisterSingleton<PLCControl>();
            //var plc = container.Resolve<PLCControl>();
            //plc.boolMonitorAction += OnBoolsChanged;
            //plc.floatMonitorAction += OnFloatsChanged;
            ReadFromJsonFile();
            PLCControl.GetInstance.Start(NetInfo);
            PLCControl.GetInstance.boolMonitorAction += OnBoolsChanged;
            PLCControl.GetInstance.floatMonitorAction += OnFloatsChanged;
            floatList.RegisterAction(OnFloatListChanged);
            boolList.RegisterAction(OnBoolListChanged);
            _eventAgg.GetEvent<PLCMsgEvent>().Subscribe(OnHttpCommand);
        }

        private void ReadFromJsonFile()
        {
            try
            {
                string jsonFromFile = File.ReadAllText(jsonFilePath);
                NetInfo = JsonConvert.DeserializeObject<NetInfo>(jsonFromFile);
            }
            catch (Exception ex)
            {
                _logger.Error("PLC--ReadFromJsonFile:" + ex);
            }
        }

        private void OnAxisCommand2(string cmd)
        {
            char[] separators = new char[] { '|' };
            string[] parts = cmd.Split(separators);
            if (parts.Length < 2)
                return;
            switch (parts[0]) {
                case "TopCamera":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopCam, parts[1]);
                    break;
                case "BottomCamera":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.BottomCam, parts[1]);
                    break;
                case "TopBeltElevating":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopBeltElevating, parts[1]);
                    break;
                case "Light":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.LightElevating, parts[1]);
                    break;
                case "InletBelt":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.InletBelt, parts[1]);
                    break;
                case "OutletBelt":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.OutletBelt, parts[1]);
                    break;
                case "TopBelt":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopBelt, parts[1]);
                    break;
                case "Barrier":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.Barrier, parts[1]);
                    break;
            }
        }

        private void OnAxisCommand(string cmd)
        {
            char[] separators = new char[] { '|' };
            string[] parts = cmd.Split(separators);
            if (parts.Length < 2)
                return;
            switch (parts[0])
            {
                case "TopCamera":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopCam, parts[1]);
                    break;
                case "BottomCamera":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.BottomCam, parts[1]);
                    break;
                case "TopBeltElevating":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopBeltElevating, parts[1]);
                    break;
                case "Light":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.LightElevating, parts[1]);
                    break;
                case "InletBelt":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.InletBelt, parts[1]);
                    break;
                case "OutletBelt":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.OutletBelt, parts[1]);
                    break;
                case "TopBelt":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopBelt, parts[1]);
                    break;
                case "Barrier":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.Barrier, parts[1]);
                    break;
            }
        }

        private void OnMouseDownCommand(MouseButtonEventArgs e)
        {
            if (e.Source is Button btn)
            {
                var cmd = btn.CommandParameter as string;
                OnAxisCommand(cmd);
            }
        }

        private void OnMouseUpCommand(MouseButtonEventArgs e)
        {
            if (e.Source is Button btn)
            {
                var cmdStr = btn.CommandParameter as string;
                char[] separators = new char[] { '|' };
                string[] parts = cmdStr.Split(separators);
                if (parts[0] == "Barrier")
                    return;
                if (parts[1] == "+" || parts[1] == "-")
                {
                    var cookedCmd = parts[0] + "|" + "!";
                    OnAxisCommand(cookedCmd);
                }                   
            }
        }
        private void OnBoolCommand(string cmd)
        {
            switch (cmd)
            {
                case "Start":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Start, true, true);
                    break;
                case "Stop":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Stop, true, true);
                    break;
                case "Reset":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Reset, true, true);
                    break;
                case "Single":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.SingleOrCycle, false);
                    break;
                case "Cycle":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Start, true);
                    break;
            }
        }
        private void OnBoolListChanged(string name, bool val)
        { 
            switch(name)
            {
                case "循环模式":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.SingleOrCycle, val);
                    break;
                case "背景光源启用":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.BackLight, val);
                    break;
                case "1号鼓风机启动":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Blower1, val);
                    break;
                case "2号鼓风机启动":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Blower2, val);
                    break;
                case "1号鼓风机换向阀启动":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.ChangeValve11, val);
                    break;
                case "2号鼓风机换向阀启动":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.ChangeValve12, val);
                    break;
                case "相机升降轴(启用/禁用)":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.CamElevatingAxisEnable, val);
                    break;
                case "上吸附升降轴(启用/禁用)":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.TopBeltAxisEnable, val);
                    break;
                case "1号鼓风机(启用/禁用)":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Blower1Enable, val);
                    break;
                case "2号鼓风机(启用/禁用)":
                    PLCControl.GetInstance.BoolControl(PLCControl.BoolType.Blower2Enable, val);
                    break;
            }
        }
        private void OnBoolsChanged(bool[] bools)
        {
            for(int i = 0; i < bools.Length; i++)
            {
                monitorList[i].BoolValue = bools[i];
            }
        }
        private void OnFloatsChanged(float[] floats)
        {
            axisPos.TopCamAxisPos = floats[0];
            axisPos.BottomCamAxisPos = floats[1];
            axisPos.TopElevatingAxisPos = floats[2];
            axisPos.LightElevatingAxisPos = floats[3];
        }
        private void OnFloatListChanged(string name, float val)
        {
            switch (name)
            {
                case "进料皮带轴速度":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.InletBelt, "s", val);
                    break;
                case "出料皮带轴速度":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.OutletBelt, "s", val);
                    break;
                case "上吸附皮带轴速度":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopBelt, "s", val);
                    break;
                case "上相机轴速度":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopCam, "s", val);
                    break;
                case "下相机轴速度":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.BottomCam, "s", val);
                    break;
                case "上吸附皮带升降轴速度":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.TopBeltElevating, "s", val);
                    break;
                case "光源升降轴速度":
                    PLCControl.GetInstance.AxisControl(PLCControl.AxisType.LightElevating, "s", val);
                    break;
                case "皮带自动运行速度":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.BeltAutoSpeed, val);
                    break;
                case "皮带返回速度":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.BeltReturnSpeed, val);
                    break;
                case "PCB板长度":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.PCBLength, val);
                    break;
                case "PCB板厚度":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.PCBThickness, val);
                    break;
                case "上相机基准位置":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.TopCamRefPos, val);
                    break;
                case "下相机基准位置":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.BottomCamRefPos, val);
                    break;
                case "上吸附升降行程":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.TopElevatingJourney, val);
                    break;
                case "挡停至光源距离":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.DistanceFromBarriarToLight, val);
                    break;
                case "分频脉冲数":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.PulseNumber, val, true);
                    break;
                case "相机触发延时":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.CamTriggerDelay, val, true);
                    break;
                case "挡停抬起延时":
                    PLCControl.GetInstance.ValueControl(PLCControl.ValueType.BarrierLiftupDelay, val, true);
                    break;
            }
        }
        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
            //do something
        }
    }
}